package com.yuntsg.subject_database.util;

import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.alibaba.fastjson.JSONObject;
import com.github.houbb.pinyin.util.PinyinHelper;
import com.yuntsg.subject_database.entity.PublicEntity;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PublicUtils {
    // 去作者的空格，统一的标准。
    public static String authorBlankSpace(String auth) {
        return auth.replace("\uE3C7", "").replace("\uE492", "").replace("\uE3A3", "").replace("\uE1DD", "").replace("\uE09C", "").replace("\uE0B0", "").replace("-", "").replace(",", "").replace(".", "").replaceAll(" +", "").replace("  ", "").replace(" ", "").toLowerCase().trim();
    }

    // 最大值max：满分full = 当前值now：X，X 为当前值相对应的得分，公式为：X = now * full / max
    public static Double countScore(Double now, Double full, Double max) {
        if (max != 0.0) {
//            return OftenUtils.Arith.div(OftenUtils.Arith.mul(now, full), max);
            return (now * full) / max;
        }
        return 0.0;
    }

    // 不同的月份，转换为不同的得分，12为0.996分，1月为0.08分，没写月份的为0.0分，即每新加一个月，值增加0.083。
    public static Double getDateScore(String str) {
        if (null == str) {
            return 0.0;
        }
        str = str.toUpperCase().trim();
        if (str.contains("DEC")) {
            return 0.996;
        }
        if (str.contains("NOV")) {
            return 0.913;
        }
        if (str.contains("OCT")) {
            return 0.83;
        }
        if (str.contains("SEP")) {
            return 0.747;
        }
        if (str.contains("AUG")) {
            return 0.664;
        }
        if (str.contains("JUL")) {
            return 0.581;
        }
        if (str.contains("JUN")) {
            return 0.498;
        }
        if (str.contains("MAY")) {
            return 0.415;
        }
        if (str.contains("APR")) {
            return 0.332;
        }
        if (str.contains("MAR")) {
            return 0.249;
        }
        if (str.contains("FEB")) {
            return 0.163;
        }
        if (str.contains("JAN")) {
            return 0.083;
        }
        return 0.0;
    }

    // 现有基础得分score，如果Map包含某个名字（name），可以得到该名字的相对应得分，则返回两个得分的累加值，如果不包含直接返回基础分score。
    public static Double addSumDouble(Map<String, Double> strDoubleMap, String name, Double score) {
        if (strDoubleMap.containsKey(name)) {
            return score + strDoubleMap.get(name);
        }
        return score;
    }

    // 获取指定的两个字符串的相似得分，分五种计算，分别是相似度、字符串包含的个数，连续字符串包含的个数，最后返回得分值。
    public static Double getScore(String from, String save, Integer tiMinLen) {
        int lenFrom = from.length();
        Set<String> fromSet = getSet(from);
        int lenSave = save.length();
        Set<String> saveSet = getSet(save);
        double score = 0.0;
        if (lenFrom > tiMinLen && lenSave > tiMinLen) {
            double textSimilarity = OftenUtils.getSimilarityRatio(OftenUtils.strSort(save), OftenUtils.strSort(from));
            int authContainMailNum = 0;
            for (int i = 0; i < from.length(); i++) {
                if (save.contains(from.split("")[i])) {
                    authContainMailNum++;
                }
            }
            double authContainMailScore = OftenUtils.Arith.mul(OftenUtils.Arith.div(authContainMailNum, lenFrom), 1.0);
            int mailContainAuthNum = 0;
            for (int j = 0; j < save.length(); j++) {
                if (from.contains(save.split("")[j])) {
                    mailContainAuthNum++;
                }
            }
            double mailContainAuthScore = OftenUtils.Arith.mul(OftenUtils.Arith.div(mailContainAuthNum, lenSave), 1.0);
            int mailContinuousSameAuthNum = 1;
            for (String str : saveSet) {
                if (fromSet.contains(str)) {
                    if (str.length() > mailContinuousSameAuthNum) {
                        mailContinuousSameAuthNum = str.length();
                    }
                }
            }
            double ContinuousSameScore1 = OftenUtils.Arith.mul(OftenUtils.Arith.div(mailContinuousSameAuthNum, lenFrom), 0.5);
            int authContinuousSameMailNum = 1;
            for (String str : fromSet) {
                if (saveSet.contains(str)) {
                    if (str.length() > authContinuousSameMailNum) {
                        authContinuousSameMailNum = str.length();
                    }
                }
            }
            double ContinuousSameScore2 = OftenUtils.Arith.mul(OftenUtils.Arith.div(authContinuousSameMailNum, lenSave), 0.5);
            score = OftenUtils.Arith.div((textSimilarity + authContainMailScore + mailContainAuthScore + ContinuousSameScore1 + ContinuousSameScore2), 4);
        }
        return score;
    }

    /**
     * 各种类型的数据解析：位数的限定，WOS为15位，EJ EB CJ CB 四种 8-9 位的数字，PM 1-8位且小于 50000000 的数字，GG GGSX 为9位数字，除了WOS外，文献ID号均不得以 0 开头，各种类型的员工代码只能为一个字母，不能是数字 。
     * PM 1 ; UT 2 ; GG 3 ; EB 4 ; EJ 5 ; CB 6 ; CJ 7
     */
    public static String getFileId(String str) {
        if (null == str) {
            return "";
        }
        // https://utswmed-ir.tdl.org/bitstream/handle/2152.5/5772/PWS%20Paper%20Supplemental%20Tables[2].pdf?sequence=1|Oligonucleotide Primer Sequences Source ir tdl org SO 2018[GGT915422624].pdf
        Matcher matcher = Pattern.compile("\\[([0-9]+)\\]").matcher(str);
        if (matcher.find()) {
            str = str.replace(matcher.group(0), "");
        }
        str = str.replaceAll(" +", "").toUpperCase().replace("[PMID[PMID", "[PMID").replace("].PDF.PDF", "].PDF").replace("].PDF(1).PDF", "].PDF").replace("].PDF(2).PDF", "].PDF").replace("].PDF(3).PDF", "].PDF");
        if (str.endsWith(".PDF")) {
            int pmStart = str.indexOf("[PMID");
            if (pmStart != -1) {
                int pmEnd = str.toUpperCase().indexOf("].PDF");
                if (pmEnd != -1 && (pmEnd - pmStart) > 6 && NumberUtil.isInteger(str.substring(pmStart + 6, pmEnd))) {
                    int id = Integer.parseInt(str.substring(pmStart + 6, pmEnd));
                    if (id < 50000000 && !str.substring(pmStart + 6).startsWith("0")) {
                        if (str.substring(pmStart + 5, pmStart + 6).matches("[a-zA-Z]+")) {
                            return "PM" + str.substring(pmStart + 6, pmEnd);
                        }
                    }
                }
            }
            int utStart = str.indexOf("[WOS");
            if (utStart != -1) {
                int utEnd = str.toUpperCase().indexOf("].PDF");
                if (utEnd != -1 && (utEnd - utStart) > 5 && str.toUpperCase().substring(utStart + 5, utEnd).length() == 15) {
                    if (str.substring(utStart + 4, utStart + 5).matches("[a-zA-Z]+")) {
                        return "UT" + str.substring(utStart + 5, utEnd);
                    }
                }
            }
            int ggStart = str.indexOf("[GG");
            if (ggStart != -1) {
                int ggEnd = str.toUpperCase().indexOf("].PDF");
                if (ggEnd != -1 && (ggEnd - ggStart) > 4 && NumberUtil.isInteger(str.substring(ggStart + 4, ggEnd))) {
                    int id = Integer.parseInt(str.substring(ggStart + 4, ggEnd));
                    if (id > 900000000 && id < 1000000000 && !str.substring(ggStart + 4).startsWith("0")) {
                        if (str.substring(ggStart + 3, ggStart + 4).matches("[a-zA-Z]+")) {
                            return "GG" + str.substring(ggStart + 4, ggEnd);
                        }
                    }
                }
            }
            int ggsxStart = str.indexOf("[GGSX");
            if (ggsxStart != -1) {
                int ggsxEnd = str.toUpperCase().indexOf("].PDF");
                if (ggsxEnd != -1 && (ggsxEnd - ggsxStart) > 6 && NumberUtil.isInteger(str.substring(ggsxStart + 6, ggsxEnd))) {
                    int id = Integer.parseInt(str.substring(ggsxStart + 6, ggsxEnd));
                    if (id > 900000000 && id < 1000000000 && !str.substring(ggsxStart + 6).startsWith("0")) {
                        if (str.substring(ggsxStart + 5, ggsxStart + 6).matches("[a-zA-Z]+")) {
                            return "GG" + str.substring(ggsxStart + 6, ggsxEnd);
                        }
                    }
                }
            }
            int cbStart = str.indexOf("[CBID");
            if (cbStart != -1) {
                int cbEnd = str.toUpperCase().indexOf("].PDF");
                if (cbEnd != -1 && (cbEnd - cbStart) > 6 && NumberUtil.isInteger(str.substring(cbStart + 6, cbEnd))) {
                    int id = Integer.parseInt(str.substring(cbStart + 6, cbEnd));
                    if (id > 10000000 && id < 999999999 && !str.substring(cbStart + 6).startsWith("0")) {
                        if (str.substring(cbStart + 5, cbStart + 6).matches("[a-zA-Z]+")) {
                            return "CB" + str.substring(cbStart + 6, cbEnd);
                        }
                    }
                }
            }
            int cjStart = str.indexOf("[CJID");
            if (cjStart != -1) {
                int cjEnd = str.toUpperCase().indexOf("].PDF");
                if (cjEnd != -1 && (cjEnd - cjStart) > 6 && NumberUtil.isInteger(str.substring(cjStart + 6, cjEnd))) {
                    int id = Integer.parseInt(str.substring(cjStart + 6, cjEnd));
                    if (id > 10000000 && id < 999999999 && !str.substring(cjStart + 6).startsWith("0")) {
                        if (str.substring(cjStart + 5, cjStart + 6).matches("[a-zA-Z]+")) {
                            return "CJ" + str.substring(cjStart + 6, cjEnd);
                        }
                    }
                }
            }
            int ebStart = str.indexOf("[EBID");
            if (ebStart != -1) {
                int ebEnd = str.toUpperCase().indexOf("].PDF");
                if (ebEnd != -1 && (ebEnd - ebStart) > 6 && NumberUtil.isInteger(str.substring(ebStart + 6, ebEnd))) {
                    int id = Integer.parseInt(str.substring(ebStart + 6, ebEnd));
                    if (id > 10000000 && id < 999999999 && !str.substring(ebStart + 6).startsWith("0")) {
                        if (str.substring(ebStart + 5, ebStart + 6).matches("[a-zA-Z]+")) {
                            return "EB" + str.substring(ebStart + 6, ebEnd);
                        }
                    }
                }
            }
            int ejStart = str.indexOf("[EJID");
            if (ejStart != -1) {
                int ejEnd = str.toUpperCase().indexOf("].PDF");
                if (ejEnd != -1 && (ejEnd - ejStart) > 6 && NumberUtil.isInteger(str.substring(ejStart + 6, ejEnd))) {
                    int id = Integer.parseInt(str.substring(ejStart + 6, ejEnd));
                    if (id > 10000000 && id < 999999999 && !str.substring(ejStart + 6).startsWith("0")) {
                        if (str.substring(ejStart + 5, ejStart + 6).matches("[a-zA-Z]+")) {
                            return "EJ" + str.substring(ejStart + 6, ejEnd);
                        }
                    }
                }
            }
            if (str.length() == 12) {
                int bookEnd = str.indexOf(".PDF");
                if (bookEnd != -1 && NumberUtil.isInteger(str.substring(0, bookEnd))) {
                    int id = Integer.parseInt(str.substring(0, bookEnd));
                    if (id > 10000000 && id < 99999999 && !str.startsWith("0")) {
                        return "EB" + str.substring(0, bookEnd);
                    }
                }
            }
        }
        return "";
    }

    //删除拼音中的音调
    public static String rePy(String str) {
        return str.toLowerCase().replace("ā", "a").replace("à", "a").replace("á", "a").replace("ǎ", "a").replace("ě", "e").replace("é", "e").replace("ē", "e").replace("è", "e")
                .replace("ī", "i").replace("ǐ", "i").replace("ì", "i").replace("í", "i").replace("ó", "o").replace("ō", "o").replace("ǒ", "o").replace("ò", "o")
                .replace("ù", "u").replace("ǔ", "u").replace("ū", "u").replace("ú", "u").replace("ü", "u").replace("ǚ", "u").replace("ǜ", "u").replace("ǖ", "u")
                .replace("ǘ", "u").replace("ń", "n").replace("\uE7C8", "n").replace("ň", "n").replace("ɡ", "g").replaceAll(" +", " ").trim();
    }

    // 正则获取出现汉字及之后的字符串，比如：COMPUTER SCIENCE, INFORMATION SYSTEMS计算机：CT系统 ，如果取不到，则全部都加入List。
    public static String getMatcher(String str) {
        if (null != str && str.length() > 1) {
            Matcher matcher = Pattern.compile("([\\u4e00-\\u9fa5].*)").matcher(str);
            if (matcher.find()) {
                return matcher.group(1).trim();
            }
            return str.trim();
        }
        return "";
    }

    // 获取全写的拼音：翁彦琴-> weng yanqin
    public static String getPiYi(String cnName, Map<String, String> baiJiaXing) {
        if (cnName.length() < 2) {
            return rePy(PinyinHelper.toPinyin(cnName));
        }
        String piYi = "";
        for (Map.Entry<String, String> entry : baiJiaXing.entrySet()) {
            if (cnName.startsWith(entry.getKey())) {
                String mapKey = entry.getKey();
                String fanYi = cnName.substring(cnName.indexOf(mapKey) + mapKey.length());
                piYi = entry.getValue() + " " + rePy(PinyinHelper.toPinyin(fanYi)).replaceAll(" +", "");
                break;
            }
        }
        if (piYi.length() < 1) {
            piYi = rePy(PinyinHelper.toPinyin(cnName.substring(0, 1))) + " " + rePy(PinyinHelper.toPinyin(cnName.substring(1))).replaceAll(" +", "");
        }
        return piYi;
    }

    // 获取全写的拼音：翁彦琴-> weng yan qin，带空格
    public static String getPiYiSpace(String cnName, Map<String, String> baiJiaXing) {
        if (cnName.length() < 2) {
            return rePy(PinyinHelper.toPinyin(cnName));
        }
        String piYi = "";
        for (Map.Entry<String, String> entry : baiJiaXing.entrySet()) {
            if (cnName.startsWith(entry.getKey())) {
                String mapKey = entry.getKey();
                String fanYi = cnName.substring(cnName.indexOf(mapKey) + mapKey.length());
                piYi = entry.getValue() + " " + rePy(PinyinHelper.toPinyin(fanYi)).replaceAll(" +", " ");
                break;
            }
        }
        if (piYi.length() < 1) {
            piYi = rePy(PinyinHelper.toPinyin(cnName.substring(0, 1))) + " " + rePy(PinyinHelper.toPinyin(cnName.substring(1))).replaceAll(" +", " ");
        }
        return piYi;
    }

    //获取简写的拼音：翁彦琴-> weng yq
    public static String getSimpPiYin(String str, Map<String, String> baiJiaXing) {
        Map<String, String> nullMap = new HashMap<>();
        String simpPiYin = "";
        List<String> list = Arrays.asList(str.replace(" ", "").split(""));
        String last = "";
        String name = "";
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            if (i == 0) {
                if (OftenUtils.isContainChinese(s)) {
                    last = getPiYi(s, baiJiaXing);
                } else {
                    last = rePy(s);
                }
            } else {
                if (OftenUtils.isContainChinese(s)) {
                    name += getPiYi(s, nullMap).substring(0, 1);
                } else {
                    name += rePy(s);
                }
            }
        }
        simpPiYin = last + " " + name;
        return simpPiYin;
    }

    //获取简写的拼音：翁彦琴-> weng yq
    public static String getSimpPiYinSpace(String str, Map<String, String> baiJiaXing) {
        Map<String, String> nullMap = new HashMap<>();
        String simpPiYin = "";
        List<String> list = Arrays.asList(str.replace(" ", "").split(""));
        String last = "";
        String name = "";
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            if (i == 0) {
                if (OftenUtils.isContainChinese(s)) {
                    last = getPiYi(s, baiJiaXing);
                } else {
                    last = rePy(s);
                }
            } else {
                if (OftenUtils.isContainChinese(s)) {
                    name += " " + getPiYi(s, nullMap).substring(0, 1);
                } else {
                    name += " " + rePy(s);
                }
            }
        }
        simpPiYin = last + " " + name;
        return simpPiYin.replaceAll(" +", " ").trim();
    }

    // 自动判断文件的编码格式，这里要求必须为.txt结尾的文件。
    public static String codeString(String filePath) {
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
        try {
            boolean checked = false;
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
            bis.mark(0); // 读者注： bis.mark(0);修改为 bis.mark(100);我用过这段代码，需要修改上面标出的地方。
            // Wagsn注：不过暂时使用正常，遂不改之
            int read = bis.read(first3Bytes, 0, 3);
            if (read == -1) {
                bis.close();
                return charset; // 文件编码为 ANSI
            } else if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
                charset = "UTF-16LE"; // 文件编码为 Unicode
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
                charset = "UTF-16BE"; // 文件编码为 Unicode big endian
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB
                    && first3Bytes[2] == (byte) 0xBF) {
                charset = "UTF-8"; // 文件编码为 UTF-8
                checked = true;
            }
            bis.reset();
            if (!checked) {
                while ((read = bis.read()) != -1) {
                    if (read >= 0xF0) {
                        break;
                    }
                    if (0x80 <= read && read <= 0xBF) { // 单独出现BF以下的，也算是GBK
                        break;
                    }
                    if (0xC0 <= read && read <= 0xDF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) { // 双字节 (0xC0 - 0xDF)
                            // (0x80 - 0xBF),也可能在GB编码内
                            continue;
                        } else {
                            break;
                        }
                    } else if (0xE0 <= read && read <= 0xEF) { // 也有可能出错，但是几率较小
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {
                            read = bis.read();
                            if (0x80 <= read && read <= 0xBF) {
                                charset = "UTF-8";
                                break;
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //System.out.println("--文件-> [" + path + "] 采用的字符集为: [" + charset + "]");
        return charset;
    }

    //获取百家姓
    public static Map<String, String> getBJX() {
        Map<String, String> map = new HashMap<>();
        map.put("薄", "bo");
        map.put("卜", "bu");
        map.put("曾", "zeng");
        map.put("查", "zha");
        map.put("仇", "qiu");
        map.put("单", "shan");
        map.put("都", "du");
        map.put("佴", "nai");
        map.put("皇甫", "huangpu");
        map.put("解", "xie");
        map.put("阚", "kan");
        map.put("乐", "yue");
        map.put("乐正", "yuezheng");
        map.put("缪", "miao");
        map.put("能", "nai");
        map.put("乜", "nie");
        map.put("拓跋", "tuoba");
        map.put("翟", "zhai");
        map.put("子车", "ziju");
        return map;
    }

    // 判断翻译是否有误，中文的以空切割，英文的空格切割，如果不重复的个数的3倍仍小于总长度，则认为是翻译不正确的。比如：
    public static boolean translateError(String str) {
        if (OftenUtils.isContainChinese(str)) {
            String[] list = str.replaceAll(" +", "").split("");
            Set<String> set = new HashSet<>(Arrays.asList(list));
            return set.size() * 5 < list.length;
        } else {
            String[] list = str.replaceAll(" +", " ").split(" ");
            Set<String> set = new HashSet<>(Arrays.asList(list));
            return set.size() * 6 < list.length;
        }
    }

    public static Set<String> readPinYin() throws SQLException {
        Set<String> pinYinSet = new ConcurrentHashSet<>();
        String pinYinTable = "scholar.help_chinese_change_pin_yin";
        List<Entity> tableData = Db.use().query("select pin_yin from " + pinYinTable);
        tableData.parallelStream().forEach(entity -> {
            if (null != entity && null != entity.getStr("pin_yin") && entity.getStr("pin_yin").length() > 1) {
                pinYinSet.add(entity.getStr("pin_yin").toLowerCase().trim());
            }
        });
        return pinYinSet;
    }

    // 获取基金字段的值，取Top并转为List输出。
    public static List<String> getFundList(String fundField) {
        List<String> fundListTop = OftenUtils.strToList(fundField);
        List<String> list = new ArrayList<>();
        for (String str : fundListTop) {
            PublicEntity.TopLower TopLower = JSONObject.parseObject(str, PublicEntity.TopLower.class);
            String fund = TopLower.getTop().trim();
            if (fund.length() > 3) {
                list.add(fund);
            }
        }
        return list;
    }

    //获取标准的单位名称以及标准的部门名称，建成Map，结构为：自由的词，对应标准的词
    public static void getStandardUnit(String table, Map<String, Map<String, PublicEntity.TopLower>> ruleMap) throws SQLException {
        String select = "`info`,`branch`,`hospital`,`standard`,`subordinate`,`exclude`,`type`,`city`";
        List<Entity> tableData = Db.use().query("select " + select + " from " + table);
        for (Entity entry : tableData) {
            String entryInfo = OftenUtils.getStrField(entry, "info");
            String entryType = OftenUtils.getStrField(entry, "type");
            if (entryInfo.length() > 2 && entryType.length() > 2) {
                PublicEntity.TopLower topLower = new PublicEntity.TopLower();
                String entryExclude = OftenUtils.getStrField(entry, "exclude");
                if (entryExclude.length() > 1) {
                    Set<String> excludeSet = new HashSet<>();
                    String[] strS = entryExclude.split("\\|");
                    for (String str : strS) {
                        if (str.trim().length() > 1) {
                            excludeSet.add(str.toLowerCase().trim());
                        }
                    }
                    topLower.setMustExclude(excludeSet);
                }
                String entrySubordinate = OftenUtils.getStrField(entry, "subordinate");
                if (entrySubordinate.length() > 1) {
                    topLower.setLower(reUnit(entrySubordinate));
                }
                String info = reUnit(entryInfo);
                String code = entryType.toLowerCase().trim();
                String entryStandard = OftenUtils.getStrField(entry, "standard");
                if (entryStandard.length() > 1) {
                    topLower.setTop(reUnit(entryStandard));
                    if (info.length() > 1 && code.length() > 1) {
                        putRuleMap(ruleMap, code, info, topLower);
                    }
                }
                // 上面的为基金fund、院系coll、部门dept，此三个的top均在字段"standard"中，下面的为大学和医院，如果大学（分校）有值或者医院有值，均保存进去，而必须排除也使用上面的值。
                // 此处暂不考虑总校及分校以及国家等，用分校主要原因是同名同姓大于300时，最多限定在分校，若是总校，范围太大了。此处要求城市必有值，也就是1014版的单位规范不能用了。
                String entryCity = OftenUtils.getStrField(entry, "city");
                if (entryCity.length() > 1) {
                    String entryUniv = OftenUtils.getStrField(entry, "branch");
                    if (entryUniv.length() > 3) {
                        topLower.setTop(reUnit(entryUniv));
                        putRuleMap(ruleMap, "univ", info, topLower);
                        putRuleMap(ruleMap, "unit", info, topLower);
                    }
                    String entryHosp = OftenUtils.getStrField(entry, "hospital");
                    if (entryHosp.length() > 3) {
                        topLower.setTop(reUnit(entryHosp));
                        putRuleMap(ruleMap, "hosp", info, topLower);
                        putRuleMap(ruleMap, "unit", info, topLower);
                    }
                }
            }
        }
    }

    // 对单位（包含大学、医院、原始数据info，以及规范后的标准名称及下位词）进行规范。部分单位可能存在多个的情况，只取第一个。
    public static String reUnit(String unit) {
        if (null != unit && unit.length() > 1) {
            unit = unit.replace("，", ",").replace("。", ".").replace("“", "\"").replace("”", "\"").replace("（", "(").replace("）", ")")
                    .replace(" )", ")").replace("( ", "(").replace(" ", " ").replaceAll(" +", " ").toLowerCase().trim();
            if (unit.indexOf("|") > 3) {
                unit = unit.substring(0, unit.indexOf("|")).trim();
            }
            return unit;
        }
        return "";
    }

    // top大于1，是因为有骨科这类的
    public static void putRuleMap(Map<String, Map<String, PublicEntity.TopLower>> ruleMap, String code, String info, PublicEntity.TopLower topLower) {
        if (topLower.getTop().length() > 1) {
            ruleMap.compute(code, (k, v) -> {
                if (v == null) {
                    v = new ConcurrentHashMap<>();
                }
                v.put(info, topLower);
                return v;
            });
        }
    }

    //规范作者名字，将多个空格规范为一个，逗号前的、后的，以及点前的、后的等，给予删除。如果以点结尾，也给予删除。
    public static String reName(String name) {
        String str = name.replace("0̄", "o").replace("¹", "1").replace("\uE3C7", "").replace("\uE492", "").replace("\uE3A3", "").replace("\uE1DD", "").replace("\uE09C", "")
                .replace("\uE0B0", "").replace("①", "1").replace("⒈", "1").replace("²", "2").replace("⒉", "2").replace("³", "3").replace("⒊", "3").replace("⑤", "5")
                .replace("ʼ", "'").replace("－", "-").replace("−", "-").replace("⁻", "-").replace("‐", "-").replace("‑", "-").replace("⁃", "-").replace("‒", "-")
                .replace("–", "-").replace("—", "-").replace("―", "-").replace("！", "!").replace("﹟", "#").replace("＃", "#").replace("♯", "#").replace("＄", "$")
                .replace("﹠", "&").replace("＆", "&").replace("（", "(").replace("⟨", "(").replace("）", ")").replace("⟩", ")").replace("⁎", "*").replace("＊", "*")
                .replace("，", ",").replace("﹒", ".").replace("．", ".").replace("。", ".").replace("∙", ".").replace("／", "/").replace("⁄", "/").replace("∕", "/")
                .replace("⧸", "/").replace("：", ":").replace("；", ";").replace("＠", "@").replace("［", "[").replace("【", "[").replace("﹝", "[").replace("〔", "[")
                .replace("〖", "[").replace("＼", "\\").replace("⧹", "\\").replace("］", "]").replace("】", "]").replace("﹞", "]").replace("〕", "]").replace("〗", "]")
                .replace("＿", "_").replace("˜", "~").replace("∼", "~").replace("˜", "~").replace("∼", "~").replace("＋", "+").replace("‹", "<").replace("〈", "<")
                .replace("＜", "<").replace("〉", ">").replace("＞", ">").replace("ａ", "a").replace("ª", "a").replace("á", "a").replace("à", "a").replace("ȧ", "a")
                .replace("â", "a").replace("ä", "a").replace("ǎ", "a").replace("ă", "a").replace("ā", "a").replace("ã", "a").replace("å", "a").replace("ą", "a")
                .replace("ấ", "a").replace("ầ", "a").replace("ắ", "a").replace("ằ", "a").replace("ǻ", "a").replace("ẫ", "a").replace("ẵ", "a").replace("ả", "a")
                .replace("ȁ", "a").replace("ȃ", "a").replace("ạ", "a").replace("ậ", "a").replace("ẚ", "a").replace("ặ", "a").replace("ɐ", "a").replace("ɑ", "a")
                .replace("α", "a").replace("ά", "a").replace("ᾰ", "a").replace("ᾶ", "a").replace("а", "a").replace("ӓ", "a").replace("ӑ", "a").replace("ｂ", "b")
                .replace("ß", "b").replace("β", "b").replace("в", "b").replace("¢", "c").replace("￠", "c").replace("€", "c").replace("ↅ", "c").replace("ｃ", "c")
                .replace("ć", "c").replace("ċ", "c").replace("ĉ", "c").replace("č", "c").replace("ç", "c").replace("ḉ", "c").replace("с", "c").replace("ҫ", "c")
                .replace("ｄ", "d").replace("ḋ", "d").replace("ď", "d").replace("đ", "d").replace("ʤ", "d").replace("ɖ", "d").replace("ｅ", "e").replace("é", "e")
                .replace("è", "e").replace("ė", "e").replace("ê", "e").replace("ë", "e").replace("ě", "e").replace("ĕ", "e").replace("ē", "e").replace("ẽ", "e")
                .replace("ę", "e").replace("ȩ", "e").replace("ế", "e").replace("ề", "e").replace("ḗ", "e").replace("ễ", "e").replace("ẻ", "e").replace("ȅ", "e")
                .replace("ȇ", "e").replace("ể", "e").replace("ẹ", "e").replace("ệ", "e").replace("е", "e").replace("ѐ", "e").replace("ё", "e").replace("ӗ", "e")
                .replace("є", "e").replace("ｆ", "f").replace("ｇ", "g").replace("ǵ", "g").replace("ġ", "g").replace("ĝ", "g").replace("ǧ", "g").replace("ğ", "g")
                .replace("ḡ", "g").replace("ģ", "g").replace("ɡ", "g").replace("ｈ", "h").replace("ℎ", "h").replace("ḧ", "h").replace("ḩ", "h").replace("ħ", "h")
                .replace("ḥ", "h").replace("ℏ", "h").replace("н", "h").replace("ћ", "h").replace("ｉ", "i").replace("ɪ", "i").replace("ı", "i").replace("í", "i")
                .replace("ì", "i").replace("î", "i").replace("ï", "i").replace("ǐ", "i").replace("ĭ", "i").replace("ī", "i").replace("ĩ", "i").replace("į", "i")
                .replace("ɨ", "i").replace("ỉ", "i").replace("ȋ", "i").replace("ị", "i").replace("ɩ", "i").replace("і", "i").replace("ї", "i").replace("ا", "i")
                .replace("إ", "i").replace("أ", "i").replace("ĳ", "j").replace("ｊ", "j").replace("ĵ", "j").replace("ǰ", "j").replace("ј", "j").replace("ｋ", "k")
                .replace("ḱ", "k").replace("ķ", "k").replace("ḵ", "k").replace("ⓚ", "k").replace("κ", "k").replace("к", "k").replace("ќ", "k").replace("ｌ", "l")
                .replace("ℓ", "l").replace("ĺ", "l").replace("ŀ", "l").replace("ľ", "l").replace("ļ", "l").replace("ƚ", "l").replace("ł", "l").replace("ᴌ", "l")
                .replace("ḽ", "l").replace("ḻ", "l").replace("ɬ", "l").replace("ȴ", "l").replace("ι", "l").replace("ί", "l").replace("ϊ", "l").replace("ῖ", "l")
                .replace("ｍ", "m").replace("ḿ", "m").replace("м", "m").replace("ｎ", "n").replace("ℕ", "n").replace("ń", "n").replace("ǹ", "n").replace("ṅ", "n")
                .replace("ň", "n").replace("ñ", "n").replace("ņ", "n").replace("ṇ", "n").replace("ṋ", "n").replace("и", "n").replace("й", "n").replace("ٍ", "o")
                .replace("َ", "o").replace("ُ", "o").replace("ِ", "o").replace("ّ", "o").replace("ð", "o").replace("ｏ", "o").replace("º", "o").replace("ℴ", "o")
                .replace("ᴓ", "o").replace("ó", "o").replace("ò", "o").replace("ȯ", "o").replace("ô", "o").replace("ö", "o").replace("ǒ", "o").replace("ŏ", "o")
                .replace("ō", "o").replace("õ", "o").replace("ǫ", "o").replace("ő", "o").replace("ố", "o").replace("ồ", "o").replace("ɵ", "o").replace("ø", "o")
                .replace("ṍ", "o").replace("ỗ", "o").replace("ǿ", "o").replace("ỏ", "o").replace("ȍ", "o").replace("ȏ", "o").replace("ơ", "o").replace("ọ", "o")
                .replace("ớ", "o").replace("ờ", "o").replace("ộ", "o").replace("ợ", "o").replace("ο", "o").replace("ό", "o").replace("ὅ", "o").replace("о", "o")
                .replace("ӧ", "o").replace("ｐ", "p").replace("ṕ", "p").replace("ρ", "p").replace("ϱ", "p").replace("ῥ", "p").replace("р", "p").replace("ｑ", "q")
                .replace("ɣ", "r").replace("ｒ", "r").replace("ŕ", "r").replace("ř", "r").replace("ŗ", "r").replace("ｓ", "s").replace("ś", "s").replace("ṡ", "s")
                .replace("ŝ", "s").replace("š", "s").replace("ş", "s").replace("ʂ", "s").replace("ṣ", "s").replace("ș", "s").replace("ｔ", "t").replace("ẗ", "t")
                .replace("ť", "t").replace("ţ", "t").replace("ƫ", "t").replace("ṭ", "t").replace("ț", "t").replace("τ", "t").replace("т", "t").replace("µ", "u")
                .replace("ｕ", "u").replace("ú", "u").replace("ù", "u").replace("û", "u").replace("ü", "u").replace("ǔ", "u").replace("ŭ", "u").replace("ū", "u")
                .replace("ũ", "u").replace("ů", "u").replace("ų", "u").replace("ű", "u").replace("ʉ", "u").replace("ǘ", "u").replace("ǜ", "u").replace("ǚ", "u")
                .replace("ǖ", "u").replace("ủ", "u").replace("ȕ", "u").replace("ȗ", "u").replace("ư", "u").replace("ứ", "u").replace("ừ", "u").replace("ữ", "u")
                .replace("ự", "u").replace("μ", "u").replace("υ", "u").replace("ύ", "u").replace("ϋ", "u").replace("ΰ", "u").replace("ц", "u").replace("ｖ", "v")
                .replace("ν", "v").replace("ｗ", "w").replace("ẃ", "w").replace("ẁ", "w").replace("ŵ", "w").replace("ẅ", "w").replace("ｘ", "x").replace("х", "x")
                .replace("ӿ", "x").replace("ｙ", "y").replace("ý", "y").replace("ỳ", "y").replace("ŷ", "y").replace("ÿ", "y").replace("ỹ", "y").replace("ẙ", "y")
                .replace("ỷ", "y").replace("γ", "y").replace("у", "y").replace("ź", "z").replace("ż", "z").replace("ẑ", "z").replace("ž", "z").replace("ƶ", "z")
                .replace("·", " ").replaceAll(" +", " ").replaceAll(",+", ",").replace(", ", ",").replace(" ,", ",").replace(",", " ").replace(". ", "").replace(" .", "")
                .replace(".", "").replace("- ", "").replace(" -", "").replace("-", "").replace(" ?", "").replace("? ", "").replace("?", "")
                .toLowerCase().replaceAll(" +", " ").trim();
        if (str.startsWith("［日］")) {
            str = str.substring("［日］".length()).trim();
        }
        if (str.startsWith("［俄］")) {
            str = str.substring("［俄］".length()).trim();
        }
        if (str.startsWith("［英」")) {
            str = str.substring("［英」".length()).trim();
        }
        if (str.startsWith("［美］")) {
            str = str.substring("［美］".length()).trim();
        }
        if (str.startsWith("［法］")) {
            str = str.substring("［法］".length()).trim();
        }
        if (str.startsWith("［德］")) {
            str = str.substring("［德］".length()).trim();
        }
        if (str.startsWith("/")) {
            str = str.substring("/".length()).trim();
        }
        return str;
    }

    // auth可以是字段key，也可以是info，用来还原作者最初的写法。
    public static String getOriginalAuth(String type, String equals, String auth, Map<String, PublicEntity.EnAuthAndCnAuth> originalAuthMap) {
        if (type.equals(equals) && auth.startsWith("[")) {
            List<String> enAuList = OftenUtils.strToList(auth);
            for (String enAu : enAuList) {
                if (originalAuthMap.containsKey(enAu)) {
                    PublicEntity.EnAuthAndCnAuth enAuthAndCnAuth = originalAuthMap.get(enAu);
                    if (enAuthAndCnAuth.getCnAuth().length() > 1) {
                        auth = enAuthAndCnAuth.getCnAuth();
                        break;
                    } else {
                        if (enAuthAndCnAuth.getEnAuth().length() > 1) {
                            auth = enAuthAndCnAuth.getEnAuth();
                        }
                    }
                }
            }
        }
        return auth;
    }

    // 执行插表。
//    public static void insertTable(String saveTable, String key, String value, String code, String type, Integer rank, Double score, Integer num, String specialist, Integer jourId, String info, String aidList,
//                                   List<PublicEntity.TableField> tableList, boolean isInsertTable, Map<String, PublicEntity.EnAuthAndCnAuth> originalAuthMap) {
    public static void insertTable(String saveTable, String key, String value, String code, String type, Integer rank, Double score, Integer num, String specialist, Integer jourId, String info, String aidList,
                                   List<PublicEntity.TableField> tableList, boolean isInsertTable) {
//        key = getOriginalAuth(type, "核心作者", key, originalAuthMap);
//        info = getOriginalAuth(type, "作者信息", info, originalAuthMap);
        if (isInsertTable) {
            try {
                Db.use().insert(Entity.create(saveTable)
                        .set("key", key)
                        .set("value", value)
                        .set("code", code)
                        .set("type", type)
                        .set("rank", rank)
                        .set("score", OftenUtils.takeFourDigits(score))
                        .set("paper_num", num)
                        .set("specialist", specialist)
                        .set("jour_id", jourId)
                        .set("info", info)
                        .set("aid_list", aidList));
            } catch (SQLException throwables) {
                System.out.println("\033[31;1m" + "--insertTable err-- " + "\033[0m" + " key: " + key + " value: " + value + " code: " + code + " type: " + type + " rank: " + rank + " score: " + score + " num: " + num + " specialist: " + specialist + " jourId: " + jourId + " info: " + info);
                throwables.printStackTrace();
            }
        } else {
            PublicEntity.TableField tableField = new PublicEntity.TableField();
            tableField.setKey(key);
            tableField.setValue(value);
            tableField.setCode(code);
            tableField.setType(type);
            tableField.setRank(rank);
            tableField.setScore(OftenUtils.takeFourDigits(score));
            tableField.setPaperNum(num);
            tableField.setSpecialist(specialist);
            tableField.setJourId(jourId);
            tableField.setInfo(info);
            tableField.setAidList(aidList);
            tableList.add(tableField);
        }
    }

    // 以";"作为分隔点，获取第一作者，并对作者去乱字符，并进行去空格。
    public static void firstAuth(String auth, Set<String> set) {
        if (auth.indexOf(";") > 1) {
            auth = auth.substring(0, auth.indexOf(";")).trim();
        }
        if (auth.length() > 1) {
            set.add(authorBlankSpace(reName(auth)));
        }
    }

    // 将表中的dept_list字段，转换成单位ĺļ部门。比如：{"山东大学":["医学院","内科学"]} -> ["山东大学ĺļ医学院","山东大学ĺļ内科学"]
    public static List<String> getDeptList(String deptStr) {
        Set<String> deptSet = new HashSet<>();
        Map<String, String> map = OftenUtils.strToMap(deptStr);
        for (Map.Entry<String, String> entry : map.entrySet()) {
            String unit = entry.getKey();
            List<String> list = OftenUtils.strToList(entry.getValue());
            for (String dept : list) {
                deptSet.add(unit + "ĺļ" + dept);
            }
        }
        return new ArrayList<>(deptSet);
    }

    // 字符串转换为List后输出，参数len是对字符串长度的约束，一般来说List存表后的字符串应大于4位，比如：["图书馆"]
    public static List<String> strToListToLowerCase(String str) {
        Set<String> set = new HashSet<>();
        if (str.length() > 4) {
            try {
                List<String> list = JSONObject.parseArray(str, String.class);
                if (null != list && list.size() > 0) {
                    for (String s : list) {
                        if (s.length() > 0) {
                            set.add(s.toLowerCase().trim());
                        }
                    }
                    return new ArrayList<>(set);
                }
            } catch (Exception e) {
                System.out.println("\033[31;1m" + "--strToListToLowerCase err-- " + "\033[0m" + str);
            }
        }
        return new ArrayList<>();
    }

    // 返回字符串最多的连续组合
    public static Set<String> getSet(String str) {
        if (str.length() > 256) {
            str = str.substring(0, 256);
        }
        Set<String> set = new HashSet<>();
        for (int i = 0; i < str.length(); i++) {
            for (int j = str.length(); j > 1; j--) {
                if (j >= i) {
                    String temp = str.substring(i, j);
                    if (temp.length() > 1) {
                        set.add(temp);
                    }
                }
            }
        }
        return set;
    }

    // 合并作者，如果中文的拼音与英文的名称相同，则只显示中文的名称，不再显示英文的名称。拼音取2种格式的。
    public static Set<String> mergeAuth(List<String> enAuthList, List<String> cnAuthList) {
        Map<String, String> baiJiaXing = getBJX();
        Set<String> authSet = new HashSet<>();
        for (String auth : enAuthList) {
            if (auth.length() > 1) {
                authSet.add(auth);
            }
        }
        for (String auth : cnAuthList) {
            if (auth.length() > 1) {
                authSet.add(auth);
            }
        }
        Map<String, String> piYinListAndCnAuMap = new HashMap<>();
        Map<String, String> enAuListAndEnAuMap = new HashMap<>();
        Set<String> cnAuthSet = new HashSet<>();
        if (cnAuthList.size() > 0 && enAuthList.size() > 0) {
            for (String auth : authSet) {
                cnAuthSet.add(auth.replace("  ", " "));
                if (OftenUtils.isContainChinese(auth)) {
                    if (auth.trim().length() > 1) {
                        String full = OftenUtils.strSort(authorBlankSpace(getPiYi(auth, baiJiaXing)));
                        String simp = OftenUtils.strSort(authorBlankSpace(getSimpPiYin(auth, baiJiaXing)));
                        piYinListAndCnAuMap.put(full, auth);
                        piYinListAndCnAuMap.put(simp, auth);
                    }
                } else {
                    if (auth.length() > 3) {
                        enAuListAndEnAuMap.put(OftenUtils.strSort(authorBlankSpace(auth)), auth.replace("  ", " "));
                    }
                }
            }
            for (Map.Entry<String, String> entry : enAuListAndEnAuMap.entrySet()) {
                String key = entry.getKey();
                if (piYinListAndCnAuMap.containsKey(key)) {
                    String cnAuth = piYinListAndCnAuMap.get(key);
                    String enAuth = entry.getValue().replace("  ", " ");
                    cnAuthSet.remove(cnAuth);
                    cnAuthSet.remove(enAuth);
                    cnAuthSet.add(cnAuth + "(" + enAuth + ")");
                }
            }
            return cnAuthSet;
        }
        return authSet;
    }


}
